home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Workspace / Locus / Source / GroupInsPane.m < prev    next >
Text File  |  1995-06-12  |  19KB  |  871 lines

  1.  
  2. /*
  3.     Copyright 1993  Jeremy Slade.
  4.  
  5.     You are free to use all or any parts of the Locus project
  6.     however you wish, just give credit where credit is due.
  7.     The author (Jeremy Slade) shall not be held responsible
  8.     for any damages that result out of use or misuse of any
  9.     part of this project.
  10.  
  11. */
  12.  
  13. /*
  14.     Project: Locus
  15.     
  16.     Class: GroupInsPane
  17.     
  18.     Description: See GroupInsPane.h
  19.         
  20.     Original Author: Jeremy Slade
  21.     
  22.     Revision History:
  23.         Created
  24.             V.101    JGS Mon Feb  8 22:07:12 GMT-0700 1993
  25.             
  26. */
  27.  
  28. #import "GroupInsPane.h"
  29.  
  30. #import "DynamicItemSpec.h"
  31. #import "DynamicItems.h"
  32. #import "Folder.h"
  33. #import "Globals.h"
  34. #import "Group.h"
  35. #import "SendAction.h"
  36. #import "SwapView.h"
  37.  
  38.  
  39. // Group Inspector sub-modes ---------------------------------
  40. #define DISPLAYOPTS_MODE    0
  41. #define ALLOWEDTYPES_MODE    1
  42. #define DYNAMICITEMS_MODE    2
  43. char *subModeTitles[] = {
  44.     "Display Options", "Allowed Types", "Dynamic Items",
  45.     NULL
  46.  };
  47.  
  48.  
  49. @implementation GroupInsPane
  50.  
  51.  
  52. // -------------------------------------------------------------------------
  53. //   Creating, Initializing
  54. // -------------------------------------------------------------------------
  55.  
  56.  
  57. + initialize
  58. {
  59.     [self setVersion:GroupInsPane_VERSION];
  60.     return ( self );
  61. }
  62.  
  63.  
  64.  
  65. - initContent:(const NXRect *)contentRect
  66.     style:(int)aStyle
  67.     backing:(int)bufferingType
  68.     buttonMask:(int)mask
  69.     defer:(BOOL)flag
  70. {
  71.     [super initContent:contentRect
  72.         style:aStyle
  73.         backing:bufferingType
  74.         buttonMask:mask
  75.         defer:flag];
  76.     
  77.     [self setDisplayOptsMode:self];
  78.         
  79.     return ( self );
  80. }
  81.  
  82.  
  83.  
  84. - awakeFromNib
  85. /*
  86.     Perform final initializations
  87. */
  88. {
  89.     [dynamicBrowser setDoubleAction:@selector(modifyDynamicItemSpec:)];
  90.     return (self );
  91. }
  92.  
  93.  
  94.  
  95. - free
  96. {
  97.     displayOptsPane = [displayOptsPane free];
  98.     allowedTypesPane = [allowedTypesPane free];
  99.     dynamicItemsPane = [dynamicItemsPane free];
  100.     
  101.     return ( [super free] );
  102. }
  103.  
  104.  
  105.  
  106. // -------------------------------------------------------------------------
  107. //   General group stuff
  108. // -------------------------------------------------------------------------
  109.  
  110.  
  111. - (BOOL)canInspect:anObject
  112. {
  113.     return ( [anObject isKindOf:[Group class]] );
  114. }
  115.  
  116.  
  117. - showCurrent:sender
  118. /*
  119.     Show the current attributes/settings of the target in the inspector.
  120.     
  121.     NOTE: When setting the contents of a TextField, it is important to set it's text delegate to nil before setting, that reset its TextDelegate to self afterwards.  This prevents -textDidChange: messages from being sent when we are setting the contents of the field.
  122. */
  123. {
  124.     DrawInfo drawInfo;
  125.     char s[2] = " ";
  126.     
  127.     [[swapView window] disableFlushWindow];
  128.     
  129.     [nameField setTextDelegate:nil];
  130.     [nameField setStringValue:[target groupName]];
  131.     [nameField setTextDelegate:self];
  132.     
  133.     if ( [target keyEquivalent] ) s[0] = [target keyEquivalent];
  134.         else s[0] = '\0';
  135.     [keyField setTextDelegate:nil];
  136.     [keyField setStringValue:s];
  137.     [keyField setTextDelegate:self];
  138.     
  139.     [sortSwitch setState:[target doesSortItems]];
  140.     
  141.     [pathField setTextDelegate:nil];
  142.     [pathField setStringValue:[target defaultPath]];
  143.     [pathField setTextDelegate:self];
  144.     
  145.     [target getDrawInfo:&drawInfo];
  146.     [drawModeCover setTitle:ICModeTitles[drawInfo.mode]];
  147.  
  148.     [subModeCover setTitle:subModeTitles[subMode]];
  149.     [swapView swap];
  150.     switch ( subMode ) {
  151.     
  152.         case DISPLAYOPTS_MODE:
  153.             [dispOptActualImage setState:drawInfo.actualImage];
  154.             switch ( drawInfo.mode ) {
  155.                 case IC_LARGE_BROWSE:
  156.                      [[dispOptFormatCover setEnabled:YES]
  157.                          setTitle: ICFormatTitles[drawInfo.lb_nameMode]];
  158.                     [[dispOptShowPath setState:0] setEnabled:NO];
  159.                     [[dispOptTriDots setEnabled:YES]
  160.                         setState:drawInfo.lb_tridots];
  161.                     [[dispOptShowInfo1 setEnabled:YES]
  162.                         setState:drawInfo.lb_info1];
  163.                     //[[dispOptShowInfo2 setEnabled:YES]
  164.                     //    setState:drawInfo.lb_info2];
  165.                     [[dispOptSmallIcons setEnabled:NO] setState:0];
  166.                     break;
  167.                 case IC_SMALL_BROWSE:
  168.                      [[dispOptFormatCover setEnabled:YES]
  169.                          setTitle: ICFormatTitles[drawInfo.sb_nameMode]];
  170.                     [[dispOptShowPath setState:0] setEnabled:NO];
  171.                     [[dispOptTriDots setState:0] setEnabled:NO];
  172.                     [[dispOptShowInfo1 setState:0] setEnabled:NO];
  173.                     //[[dispOptShowInfo2 setState:0] setEnabled:NO];
  174.                     [[dispOptSmallIcons setEnabled:YES]
  175.                         setState:drawInfo.sb_icon];
  176.                     break;
  177.                 case IC_LARGE_ICON:
  178.                     [[dispOptFormatCover setEnabled:NO]
  179.                         setTitle:ICFormatTitles[IC_FILEONLY]];
  180.                     [[dispOptShowPath setEnabled:NO]
  181.                         setState:drawInfo.li_showName];
  182.                     [[dispOptTriDots setState:0] setEnabled:NO];
  183.                     [[dispOptShowInfo1 setState:0] setEnabled:NO];
  184.                     //[[dispOptShowInfo2 setState:0] setEnabled:NO];
  185.                     [[dispOptSmallIcons setEnabled:NO] setState:0];
  186.                     break;
  187.                 case IC_SMALL_ICON:
  188.                     [[dispOptFormatCover setEnabled:NO]
  189.                         setTitle:ICFormatTitles[IC_FILEONLY]];
  190.                     [[dispOptShowPath setEnabled:NO]
  191.                         setState:drawInfo.si_showName];
  192.                     [[dispOptTriDots setState:0] setEnabled:NO];
  193.                     [[dispOptShowInfo1 setState:0] setEnabled:NO];
  194.                     //[[dispOptShowInfo2 setState:0] setEnabled:NO];
  195.                     [[dispOptSmallIcons setEnabled:NO] setState:0];
  196.                     break;
  197.                 case IC_DRAW_UNKNOWN:
  198.                 default:
  199.                     [[dispOptFormatCover setEnabled:NO]
  200.                         setTitle:ICFormatTitles[IC_NAME_UNKNOWN]];
  201.                     [[dispOptTriDots setState:0] setEnabled:NO];
  202.                     [[dispOptShowInfo1 setState:0] setEnabled:NO];
  203.                     //[[dispOptShowInfo2 setState:0] setEnabled:NO];
  204.                     [[dispOptSmallIcons setEnabled:NO] setState:0];
  205.                     break;
  206.             }
  207.             break;
  208.             
  209.         case ALLOWEDTYPES_MODE:
  210.             [self loadAllowedTypes:self];
  211.             [allowedRestrictSwitch setState:![target doesRestrictTypes]];
  212.             [allowedRemoveButton setEnabled:NO];
  213.             [allowedField setTextDelegate:nil];
  214.             [allowedField setStringValue:""];
  215.             [allowedField setTextDelegate:self];
  216.             [allowedAddButton setEnabled:NO];
  217.             break;
  218.             
  219.         case DYNAMICITEMS_MODE:
  220.             [self loadDynamicItemSpecs:self];
  221.             [dynamicField setTextDelegate:nil];
  222.             [dynamicField setStringValue:""];
  223.             [dynamicField setTextDelegate:self];
  224.             [dynamicDisableButton setEnabled:NO];
  225.             [dynamicEnableButton setEnabled:NO];
  226.             [dynamicRemoveButton setEnabled:NO];
  227.             [dynamicAddButton setEnabled:NO];
  228.             [dynamicIntervalField setIntValue:[target updateInterval] / 60];
  229.             [dynamicIntervalSlider setIntValue:[target updateInterval] / 60];
  230.             break;
  231.             
  232.     }
  233.  
  234.     [[[swapView window] reenableFlushWindow] flushWindow];
  235.     return ( [super showCurrent:sender] );
  236. }
  237.  
  238.  
  239.  
  240. - selectNameField:sender
  241. /*
  242.     Start editing in the nameField, to immediately be able to set the name of a group.
  243. */
  244. {
  245.     [nameField selectText:self];
  246.     return ( self );
  247. }
  248.  
  249.  
  250.  
  251. - changeGroupName:sender
  252. /*
  253.     Called by nameField when editing on the field finishes
  254. */
  255. {
  256.     if ( !strlen ( [nameField stringValue] ) ) {
  257.         [nameField selectText:self];
  258.         return ( self );
  259.     }
  260.     
  261.     if ( ![[target folder] renameGroup:target to:[nameField stringValue]] ) {
  262.         [nameField selectText:self];
  263.         return ( self );
  264.     }
  265.     
  266.     return ( self );
  267. }
  268.  
  269.  
  270.  
  271. - changeGroupKey:sender
  272. /*
  273.     Called by keyField when editing on the field finishes
  274. */
  275. {
  276.     char str[2];
  277.     int i, count;
  278.     BOOL isInUse = NO;
  279.     id    folder, group, menu;
  280.     
  281.     strncpy ( str, [keyField stringValue], 1 );
  282.     str[1] = '\0';
  283.     
  284.     if ( !strlen ( str ) ) {    
  285.         // Set to no key equivalent
  286.         isInUse = NO;
  287.     } else {
  288.     
  289.         if ( !isGoodKeyEq ( str[0] ) ) { // Not a valid key equivalent
  290.             [keyField selectText:self];
  291.             return ( self );
  292.         }
  293.         
  294.         // Make sure the key is not in use my another group in the same folder
  295.         folder = [target folder];
  296.         count = [folder count];
  297.         for ( i=0; i<count; i++ ) {
  298.             if ( (group = [folder objectAt:i]) != target &&
  299.                 [group keyEquivalent] == (unsigned short)str[0] ) {
  300.                     // Key already in use
  301.                     isInUse = YES;
  302.                     break;
  303.             }
  304.         }
  305.     }
  306.     
  307.     if ( !isInUse ) {
  308.         [target setKeyEquivalent:str[0]];
  309.         i = [(menu = [[target folder] groupMenu])
  310.             indexOfItem:[target groupName]];
  311.         [[[[menu itemList] cellList] objectAt:i] setKeyEquivalent:str[0]];
  312.     }
  313.     
  314.     return ( self );
  315. }
  316.  
  317.  
  318.  
  319. - changeGroupPath:sender
  320. /*
  321.     Called by pathField when editing in the field finishes
  322. */
  323. {
  324.     if ( ![target setDefaultPath:[pathField stringValue]] ) {
  325.         [pathField selectText:self];
  326.         return ( self );
  327.     }
  328.     
  329.     return ( self );
  330. }
  331.  
  332.  
  333.  
  334. - chooseGroupPath:sender
  335. /*
  336.     This method is the action of the choosePathButton. Pops up an OpenPanel to choose the group's default path.  The OpenPanel forces them to choose a directory by setting the required type to something that (most likely) will not ever be a valid file type.
  337. */
  338. {
  339.     id    openPanel = [OpenPanel new];
  340.     
  341.     [[openPanel setTitle:"Choose Default Path"] setPrompt:"Path:"];
  342.     [[openPanel allowMultipleFiles:NO] chooseDirectories:YES];
  343.  
  344.     if ( [openPanel runModalForDirectory:[target defaultPath] file:NULL] ) {
  345.         // Ask for filename rather than directory, because -directory doesn't
  346.         // return last selected column
  347.         [target setDefaultPath:[openPanel filename]];
  348.         [self showCurrent:self];
  349.     }
  350.     
  351.     return ( self );
  352. }
  353.  
  354.  
  355.  
  356. - changeGroupSort:sender
  357. {
  358.     [target setSortItems:[sortSwitch state]];
  359.     return ( self );
  360. }
  361.  
  362.  
  363.  
  364. - changeDrawToLargeBrowse:sender
  365. {
  366.     [target setDrawMode:IC_LARGE_BROWSE];
  367.     [self showCurrent:self];
  368.     return ( self );
  369. }
  370.  
  371.  
  372.  
  373. - changeDrawToSmallBrowser:sender
  374. {
  375.     [target setDrawMode:IC_SMALL_BROWSE];
  376.     [self showCurrent:self];
  377.     return ( self );
  378. }
  379.  
  380.  
  381.  
  382. - changeDrawToLargeIcon:sender
  383. {
  384.     [target setDrawMode:IC_LARGE_ICON];
  385.     [self showCurrent:self];
  386.     return ( self );
  387. }
  388.  
  389.  
  390.  
  391. - changeDrawToSmallIcon:sender
  392. {
  393.     [target setDrawMode:IC_SMALL_ICON];
  394.     [self showCurrent:self];
  395.     return ( self );
  396. }
  397.  
  398.  
  399.  
  400. // -------------------------------------------------------------------------
  401. //   Setting the sub-mode
  402. // -------------------------------------------------------------------------
  403.  
  404.  
  405. - setDisplayOptsMode:sender
  406. {
  407.     subMode = DISPLAYOPTS_MODE;
  408.     [self showCurrent:self];
  409.     return ( self );
  410. }
  411.  
  412.  
  413.  
  414. - setAllowedTypesMode:sender
  415. {
  416.     subMode = ALLOWEDTYPES_MODE;
  417.     [self showCurrent:self];
  418.     return ( self );
  419. }
  420.  
  421.  
  422.  
  423. - setDynamicItemsMode:sender
  424. {
  425.     subMode = DYNAMICITEMS_MODE;
  426.     [self showCurrent:self];
  427.     return ( self );
  428. }
  429.  
  430.  
  431.  
  432. - swapPaneFor:sender
  433. /*
  434. T    his is SwapView's delegate method to determine which panel to show...
  435. */
  436. {
  437.     switch ( subMode ) {
  438.         case DISPLAYOPTS_MODE: return ( displayOptsPane );
  439.         case ALLOWEDTYPES_MODE: return ( allowedTypesPane );
  440.         case DYNAMICITEMS_MODE: return ( dynamicItemsPane );
  441.     }
  442.  
  443.     return ( nil );
  444. }
  445.  
  446.  
  447.  
  448. // -------------------------------------------------------------------------
  449. //   Display Options sub-mode
  450. // -------------------------------------------------------------------------
  451.  
  452.  
  453. - setFormatFullPath:sender
  454. {
  455.     switch ( [target drawMode] ) {
  456.         case IC_LARGE_BROWSE:
  457.             [target setLBNameMode:IC_FULLPATH]; break;
  458.         case IC_SMALL_BROWSE:
  459.             [target setSBNameMode:IC_FULLPATH]; break;
  460.     }
  461.     return ( self );
  462. }
  463.  
  464.  
  465.  
  466. - setFormatFileAndPath:sender
  467. {
  468.     switch ( [target drawMode] ) {
  469.         case IC_LARGE_BROWSE:
  470.             [target setLBNameMode:IC_FILEANDPATH]; break;
  471.         case IC_SMALL_BROWSE:
  472.             [target setSBNameMode:IC_FILEANDPATH]; break;
  473.     }
  474.     return ( self );
  475. }
  476.  
  477.  
  478.  
  479. - setFormatFileOnly:sender
  480. {
  481.     switch ( [target drawMode] ) {
  482.         case IC_LARGE_BROWSE:
  483.             [target setLBNameMode:IC_FILEONLY]; break;
  484.         case IC_SMALL_BROWSE:
  485.             [target setSBNameMode:IC_FILEONLY]; break;
  486.     }
  487.     return ( self );
  488. }
  489.  
  490.  
  491.  
  492. - setFormatRelative:sender
  493. {
  494.     switch ( [target drawMode] ) {
  495.         case IC_LARGE_BROWSE:
  496.             [target setLBNameMode:IC_RELATIVE]; break;
  497.         case IC_SMALL_BROWSE:
  498.             [target setSBNameMode:IC_RELATIVE]; break;
  499.     }
  500.     return ( self );
  501. }
  502.  
  503.  
  504.  
  505. - setFormatNoPath:sender
  506. {
  507.     switch ( [target drawMode] ) {
  508.         case IC_LARGE_BROWSE:
  509.             [target setLBNameMode:IC_NOPATH]; break;
  510.         case IC_SMALL_BROWSE:
  511.             [target setSBNameMode:IC_NOPATH]; break;
  512.     }
  513.     return ( self );
  514. }
  515.  
  516.  
  517.  
  518. - setShowPath:sender
  519. {
  520.     switch ( [target drawMode] ) {
  521.         case IC_LARGE_ICON:
  522.             [target setLIDrawName:[dispOptShowPath state]]; break;
  523.         case IC_SMALL_ICON:
  524.             [target setSIDrawName:[dispOptShowPath state]]; break;
  525.     }
  526.     return ( self );
  527. }
  528.  
  529.  
  530.  
  531. - setShowActualImage:sender
  532. {
  533.     [target setDrawActualImage:[dispOptActualImage state]];
  534.     return ( self );
  535. }
  536.  
  537.  
  538.  
  539. - setShowTriDots:sender
  540. {
  541.     [target setDrawTriDots:[dispOptTriDots state]];
  542.     return ( self );
  543. }
  544.  
  545.  
  546.  
  547. - setShowInfoLine:sender
  548. {
  549.     [target setDrawInfoLine1:[dispOptShowInfo1 state]];
  550.     return ( self );
  551. }
  552.  
  553.  
  554.  
  555. - setShowSmallIcon:sender
  556. {
  557.     [target setDrawSmallIcons:[dispOptSmallIcons state]];
  558.     return ( self );
  559. }
  560.  
  561.  
  562.  
  563. // -------------------------------------------------------------------------
  564. //   Allowed Types sub-mode
  565. // -------------------------------------------------------------------------
  566.  
  567.  
  568. - loadAllowedTypes:sender
  569. {
  570.     [allowedBrowser loadColumnZero];
  571.     [allowedRemoveButton setEnabled:NO];
  572.     return ( self );
  573. }
  574.  
  575.  
  576.  
  577. - allowedTypeSelected:sender
  578. /*
  579.     Called when one of the items in the allowsBrowser is clicked
  580. */
  581. {
  582.     [allowedRemoveButton setEnabled:YES];
  583.     return ( self );
  584. }
  585.  
  586.  
  587.  
  588. - changeUseRestrictions:sender
  589. /*
  590.     Called when the User Restrictions switch is clicked
  591. */
  592. {
  593.     [target setRestrictTypes:([allowedRestrictSwitch state] ? NO : YES)];
  594.     return ( self );
  595. }
  596.  
  597.  
  598.  
  599. - newAllowedType:sender
  600. /*
  601.     Called when the Add button is clicked
  602. */
  603. {
  604.     [target addAllowedType:[allowedField stringValue]];
  605.     [allowedField setStringValue:""]; // Blank the field
  606.     [self loadAllowedTypes:self];
  607.     return ( self );
  608. }
  609.  
  610.  
  611.  
  612. - removeAllowedTypes:sender
  613. /*
  614.     Called when the remove button is clicked
  615. */
  616. {
  617.     int i, count;
  618.     id list = [[allowedBrowser matrixInColumn:0] cellList];
  619.     id cell;
  620.     
  621.     count = [list count];
  622.     for ( i=0; i<count; i++ )
  623.         if ( [(cell = [list objectAt:i]) state] )
  624.             [target removeAllowedType:[cell stringValue]];
  625.     
  626.     [self loadAllowedTypes:self];
  627.     return ( self );
  628. }
  629.  
  630.  
  631.  
  632. // -------------------------------------------------------------------------
  633. //   Dynamic Items sub-mode
  634. // -------------------------------------------------------------------------
  635.  
  636.  
  637. - loadDynamicItemSpecs:sender
  638. {
  639.     [dynamicBrowser loadColumnZero];
  640.     [dynamicDisableButton setEnabled:NO];
  641.     [dynamicEnableButton setEnabled:NO];
  642.     [dynamicRemoveButton setEnabled:NO];
  643.  
  644.     return ( self );
  645. }
  646.  
  647.  
  648.  
  649. - dynamicItemSpecSelected:sender
  650. /*
  651.     Called when one of the items in the dynamicBrowser is clicked
  652. */
  653. {
  654.     [dynamicDisableButton setEnabled:YES];
  655.     [dynamicEnableButton setEnabled:YES];
  656.     [dynamicRemoveButton setEnabled:YES];
  657.  
  658.     return ( self );
  659. }
  660.  
  661.  
  662.  
  663. - newDynamicItemSpec:sender
  664. /*
  665.     Called when the dynamic Add button is clicked
  666. */
  667. {
  668.     [target addDynamicItemSpec:[dynamicField stringValue]];
  669.     [self loadDynamicItemSpecs:self];
  670.     return ( self );
  671. }
  672.  
  673.  
  674.  
  675. - modifyDynamicItemSpec:sender
  676. /*
  677.     Called when an item in the dynamic browser is double-clicked
  678. */
  679. {
  680.     // Not implemented
  681.     [self debug:10 :"Modify Dynamic Item: Not implemented\n"];
  682.     return ( self );
  683. }
  684.  
  685.  
  686.  
  687. - disableDynamicItemSpecs:sender
  688. /*
  689.     Called when the dynamic disable button is clicked
  690. */
  691. {
  692.     int i, count;
  693.     id list = [[dynamicBrowser matrixInColumn:0] cellList];
  694.     id cell;
  695.     
  696.     count = [list count];
  697.     for ( i=0; i<count; i++ )
  698.         if ( [(cell = [list objectAt:i]) state] )
  699.             [target disableDynamicItemSpec:[cell stringValue]];
  700.     
  701.     [self loadDynamicItemSpecs:self];
  702.     return ( self );
  703. }
  704.  
  705.  
  706.  
  707. - enableDynamicItemSpecs:sender
  708. /*
  709.     Called when the dynamic enable button is clicked
  710. */
  711. {
  712.     int i, count;
  713.     id list = [[dynamicBrowser matrixInColumn:0] cellList];
  714.     id cell;
  715.     
  716.     count = [list count];
  717.     for ( i=0; i<count; i++ )
  718.         if ( [(cell = [list objectAt:i]) state] )
  719.             [target enableDynamicItemSpec:[cell stringValue]];
  720.     
  721.     [self loadDynamicItemSpecs:self];
  722.     return ( self );
  723. }
  724.  
  725.  
  726.  
  727. - removeDynamicItemSpecs:sender
  728. /*
  729.     Called when the dynamic remove button is clicked
  730. */
  731. {
  732.     int i, count;
  733.     id list = [[dynamicBrowser matrixInColumn:0] cellList];
  734.     id cell;
  735.     
  736.     count = [list count];
  737.     for ( i=0; i<count; i++ )
  738.         if ( [(cell = [list objectAt:i]) state] )
  739.             [target removeDynamicItemSpec:[[list objectAt:i] stringValue]];
  740.     
  741.     [self loadDynamicItemSpecs:self];
  742.     return ( self );
  743. }
  744.  
  745.  
  746.  
  747. - setDynamicUpdateInterval:sender
  748. /*
  749.     Called by both the dynamicIntervalField and the dynamicIntervalSlider when they are changed.
  750. */
  751. {
  752.     float minutes;
  753.  
  754.     // Make sure the slider and field are showing the same value
  755.     minutes = [sender intValue];
  756.     [dynamicIntervalSlider setIntValue:minutes];
  757.     [dynamicIntervalField setIntValue:minutes];
  758.     
  759.     // Set the dynamic update interval of the group in seconds
  760.     [target setUpdateInterval:minutes * 60];
  761.     
  762.     return ( self );
  763. }
  764.  
  765.  
  766.  
  767.  
  768. // -------------------------------------------------------------------------
  769. //   Text Delegate methods
  770. // -------------------------------------------------------------------------
  771.  
  772.  
  773. - textDidChange:sender
  774. {
  775.     if ( [sender isKindOf:[Text class]] ) sender = [sender delegate];
  776.  
  777.     if ( sender == nameField ) {
  778.     } else
  779.     if ( sender == keyField ) {
  780.     } else
  781.     if ( sender == pathField ) {
  782.     } else
  783.     if ( sender == allowedField ) {
  784.         [allowedAddButton setEnabled:YES];
  785.     } else
  786.     if ( sender == dynamicField ) {
  787.         [dynamicAddButton setEnabled:YES];
  788.     }
  789.     
  790.     return ( self );
  791. }
  792.  
  793.  
  794.  
  795. - textDidEnd:sender endChar:(unsigned short)endChar
  796. /*
  797.     Make sure changes made in field get saved.  If the field was exited with a return, then it will automatically send the action (which is where it gets saved).  If the field was exited with a tab, we need to send the action ourselves.
  798. */
  799. {
  800.     if ( [sender isKindOf:[Text class]] ) sender = [sender delegate];
  801.  
  802.     if ( sender == nameField ) {
  803.         [[nameField target] perform:[nameField action] with:self];
  804.         if ( endChar == NX_CR ) [[NXApp mainWindow] makeKeyWindow];
  805.     } else
  806.     if ( sender == keyField ) {
  807.         [keyField sendAction];
  808.         if ( endChar == NX_CR ) [[NXApp mainWindow] makeKeyWindow];
  809.     } else
  810.     if ( sender == pathField ) {
  811.         [pathField sendAction];
  812.         if ( endChar == NX_CR ) [[NXApp mainWindow] makeKeyWindow];
  813.     } else
  814.     if ( sender == allowedField ) {
  815.     } else
  816.     if ( sender == dynamicField ) {
  817.     }
  818.     
  819.     return ( self );
  820. }
  821.  
  822.  
  823.  
  824. // -------------------------------------------------------------------------
  825. //   Browser delegate methods
  826. // -------------------------------------------------------------------------
  827.  
  828.  
  829. - (int)browser:sender fillMatrix:matrix inColumn:(int)column
  830. /* All the browsers use normal delegate */
  831. {
  832.     int count = 0;
  833.     id cell;
  834.     
  835.     if ( sender == allowedBrowser ) {
  836.         const char **allowedTypes = [target allowedTypes];        
  837.  
  838.         while ( allowedTypes[count] ) {
  839.             [matrix addRow];
  840.             cell = [matrix cellAt:[matrix cellCount]-1 :0];
  841.             [cell initTextCell:allowedTypes[count]];
  842.             [[cell setLoaded:YES] setLeaf:YES];
  843.             count++;
  844.         }
  845.     } else
  846.     
  847.     if ( sender == dynamicBrowser ) {
  848.         id list = [target dynamicItemSpecs]; // Get list of DynamicItemSpecs
  849.         id spec;
  850.         id enabledFont = [Font newFont:"Helvetica-Bold" size:12];
  851.         id disabledFont = [Font newFont:"Helvetica" size:12];
  852.         int i;
  853.         count = [list count];
  854.         for ( i=0; i<count; i++ ) {
  855.             spec = [list objectAt:i];
  856.             [matrix addRow];
  857.             cell = [matrix cellAt:[matrix cellCount]-1 :0];
  858.             [cell initTextCell:[spec expression]];
  859.             [cell setFont:([spec enabled] ? enabledFont : disabledFont)];
  860.             [[cell setLoaded:YES] setLeaf:YES];
  861.         }
  862.     }
  863.     
  864.     return ( count );
  865. }
  866.  
  867.  
  868.  
  869. @end
  870.  
  871.